#!/usr/bin/python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

import sys
import mrget
import gstage4
import strict_hwcfg
import strict_portage
import multiprocessing
sys.path.append('/usr/lib64/fpemud-os-sysman')
from fm_util import Util
from fm_util import InfoPrinter
from fm_util import CcacheLocalService
from fm_util import PrintLoadAvgThread
from fm_param import FmConst
from helper_pkg_warehouse import CloudOverlayDb
from helper_assist_disk import TargetFeatureAssistOs


# FIMXE:
# 1. change to lop and rop, lop is for debugging
# 2. don't re-probe machine, add parameters


mrget.init(system_or_user=True)

p = InfoPrinter(indent=int(sys.argv[1]))                        # FIXME: print should be done by infoPrinter
arch = sys.argv[2]
profile = sys.argv[3]
stage3File = sys.argv[4]
stage3DigestFile = sys.argv[5]
snapshotFile = sys.argv[6]
diskFsUuid = sys.argv[7]
wdir = gstage4.WorkDir(sys.argv[8])
bHasMemTest = (sys.argv[9] != "0")

overlayDb = CloudOverlayDb()
if not overlayDb.isUpdateComplete():
    overlayDb.update()

machine = strict_hwcfg.probe()

ftFixbug = gstage4.target_features.FixBugs()
ftKernel = gstage4.target_features.UseBbki()
ftPackageManager = gstage4.target_features.UsePortage()
ftServiceManager = gstage4.target_features.UseSystemd()
ftNoDeprecate = gstage4.target_features.DontUseDeprecatedPackagesAndFunctions()
ftUseCapability = gstage4.target_features.UseCapability()
ftPreferGnu = gstage4.target_features.PreferGnuAndGpl()
ftPreferBinPkg = gstage4.target_features.PreferBinaryPackage()
ftPreferSystemComponent = gstage4.target_features.PreferSystemComponent()
ftPreferWayland = gstage4.target_features.PreferWayland()
ftPreferBlockDeviceUAccess = gstage4.target_features.PreferBlockDeviceUAccess()
ftPreferPythonMagic = gstage4.target_features.PreferPythonMagic()
# ftNoVt = gstage4.target_features.DontUseVT()
ftDisableFstab = gstage4.target_features.DisableFstab()
ftNoPypy = gstage4.target_features.DontUsePypy()
ftNoPolkit = gstage4.target_features.DontUsePolicyKit()
ftNoLogrotate = gstage4.target_features.DontUseLogrotate()
ftNoSudo = gstage4.target_features.DontUseSudo()
ftSupportAllTermType = gstage4.target_features.SupportAllTermType()
if bHasMemTest:
    ftMemTest = gstage4.target_features.MemTest()
ftChrony = gstage4.target_features.Chrony(exclusive=True)
ftZeroConf = gstage4.target_features.UseZeroConf(service="avahi")
ftSshServer = gstage4.target_features.SshServer()
ftNetworkManager = gstage4.target_features.NetworkManager(wifi=True, exclusive=True)
ftTailorSystemd = gstage4.target_features.TailorSystemd(
    disable_items=[
        "systemd-udevd-socket-activation",
        "kmod-static-nodes",
    ],
    remove_items=[
        "systemd-battery-check",
        "systemd-boot",
        "systemd-coredump",                         # diagnosing things are beyound us
        "systemd-dissect",
        "systemd-hostnamed",                        # we don't change hostname dynamically
        "systemd-firstboot",
        "systemd-kexec",
        "systemd-localed",                          # eselect is enough
        "systemd-machined",
        "systemd-networkd",
        "systemd-oomd",
        "systemd-portabled",
        "systemd-pstore",
        "systemd-resolvd",
        "systemd-storagetm",
        "systemd-sysext",
        "systemd-sysupdate",
        "systemd-sysusers",
        "systemd-timedated",                        # eselect is enough
        "systemd-timesyncd",                        # chrony is better
        "systemd-update",
        "systemd-userdbd",
        "systemd-ssh-proxy",
        "systemd-run-generator",                    # we don't tell systemd to run something through kernel command line
        "systemd-efi-boot-generator",               # we mount /boot in initramfs so this is uneccessary
        "systemd-gpt-auto-generator",               # all the key mount point are established in initramfs, no automation needed
        "systemd-ssh-generator",
        "kernel-management",
        "fstab",
        "fs-operations",
        "ldconfig.service",                         # we update ld cache during package install, not system boot
        "initrd-facility",                          # we don't use systemd in initramfs
        "debug-facility",
    ]
)
ftTailorEselect = gstage4.target_features.TailorEselect(remove_items=[
    "kernel-module",
    "rc-module",
])
ftTailorGit = gstage4.target_features.TailorGit(add_items=[
    "http-connection-timeout-extension",
    "robust-extension",
])
ftTailorWget = gstage4.target_features.TailorWget(add_items=[
    "robust-extension",
])
ftTailorRsync = gstage4.target_features.TailorRsync(add_items=[
    "robust-extension",
])
ftAssistOs = TargetFeatureAssistOs(machine)

# step
p.printInfo("- Initializing...")
c = CcacheLocalService()
builder = None
if True:
    s = gstage4.Settings()
    s.program_name = FmConst.programName
    s.log_dir = None
    s.verbose_level = 0
    s.host_cpu_core_count = multiprocessing.cpu_count()
    s.host_memory_size = Util.getPhysicalMemorySize() * 1024 * 1024 * 1024
    s.host_cooling_level = 10 if Util.hwcfgHasFan(machine) is not None else 1
    s.host_distfiles_dir = FmConst.distDir
    if c.is_enabled():
        s.host_ccache_dir = c.get_ccache_dir()

    ts = gstage4.TargetSettings()
    ts.arch = arch
    ts.profile = profile
    ts.mirrors = strict_portage.cfg.PortageConfigDir().get_mirrors_obj().get_mirror_mapping()
    ftFixbug.update_target_settings(ts)
    ftKernel.update_target_settings(ts)
    ftPackageManager.update_target_settings(ts)
    ftServiceManager.update_target_settings(ts)
    ftNoDeprecate.update_target_settings(ts)
    ftUseCapability.update_target_settings(ts)
    ftPreferGnu.update_target_settings(ts)
    ftPreferBinPkg.update_target_settings(ts)
    ftPreferSystemComponent.update_target_settings(ts)
    ftPreferWayland.update_target_settings(ts)
    ftPreferBlockDeviceUAccess.update_target_settings(ts)
    ftPreferPythonMagic.update_target_settings(ts)
    # ftNoVt.update_target_settings(ts)
    ftDisableFstab.update_target_settings(ts)
    ftNoPypy.update_target_settings(ts)
    if bHasMemTest:
        ftMemTest.update_target_settings(ts)
    ftChrony.update_target_settings(ts)
    ftNetworkManager.update_target_settings(ts)
    ftNoPolkit.update_target_settings(ts)
    ftNoLogrotate.update_target_settings(ts)
    ftNoSudo.update_target_settings(ts)
    ftTailorSystemd.update_target_settings(ts)
    ftTailorEselect.update_target_settings(ts)
    ftTailorGit.update_target_settings(ts)
    ftTailorWget.update_target_settings(ts)
    ftTailorRsync.update_target_settings(ts)
    ftAssistOs.update_target_settings(ts)
    if c.is_enabled():
        # we use ccache if host uses ccache
        ts.build_opts.ccache = True

    builder = gstage4.Builder(s, ts, wdir)

# step
p.printInfo("- Extracting seed stage...")
with gstage4.seed_stages.GentooStage3Archive(stage3File, digest_filepath=stage3DigestFile) as ss:
    builder.action_unpack(ss)

# step
p.printInfo("- Installing gentoo repository...")
gentooRepo = gstage4.repositories.GentooSnapshot(snapshotFile)
builder.action_create_gentoo_repository(gentooRepo)

# step
p.printInfo("- Generating configurations...")
if True:
    builder.action_init_confdir()

# step
p.printInfo("- Installing overlays...")
builder.action_create_overlays([
    gstage4.repositories.UserDefinedOverlay("guru", *overlayDb.getOverlayVcsTypeAndUrl("guru")),
    gstage4.repositories.UserDefinedOverlay("mirrorshq-overlay", "git", "https://gitee.com/mirrorshq/gentoo-overlay"),
    gstage4.repositories.UserDefinedOverlay("your-own-os-overlay", "git", "https://gitee.com/your-own-os/gentoo-overlay"),
    gstage4.repositories.UserDefinedOverlay("fpemud-overlay", "git", "https://gitee.com/fpemud/gentoo-overlay"),                         # app-admin/fpemud-os-assist-disk-scripts
])

# step
with PrintLoadAvgThread(p.getIndentStr() + "- Updating world..."):
    worldSet = {
        "app-admin/barkspider",
        "app-admin/eselect",
        "app-admin/fpemud-os-assist-disk-scripts",
        "app-arch/cpio",
        "app-arch/gzip",
        "app-arch/lz4",
        "app-arch/p7zip",
        "app-arch/unzip",
        "app-arch/zip",
        "app-eselect/eselect-timezone",
        "app-editors/nano",
        "app-misc/mc",
        "app-misc/tmux",
        "app-text/tree",
        "dev-debug/strace",
        "dev-lang/python",
        "dev-python/bbki",
        "dev-vcs/git",
        "dev-vcs/subversion",
        "gui-wm/cage",
        "net-misc/rsync",
        "net-misc/wget",
        "sys-apps/dmidecode",
        "sys-apps/lm-sensors",
        "sys-apps/lshw",
        "sys-apps/smartmontools",
        "sys-boot/grub",
        "sys-apps/file",
        "sys-apps/hdparm",
        "sys-apps/nvme-cli",            # manipulate nvme device
        "sys-apps/sdparm",              # manipulate sata device
        "sys-block/parted",
        "sys-boot/os-prober",
        "sys-devel/bc",
        "sys-fs/bcache-tools",          # manipulate bcache
        "sys-fs/btrfs-progs",           # manipulate btrfs filesystem
        "sys-fs/dosfstools",            # manipulate fat filesystem
        "sys-fs/e2fsprogs",             # manipulate ext2/3/4 filesystem
        "sys-fs/exfatprogs",            # manipulate exfat filesystem
        "sys-fs/f2fs-tools",            # manipulate f2fs filesystem
        "sys-fs/lsscsi",
        "sys-fs/mtools",
        "sys-fs/ntfs3g",                # manipulate ntfs filesystem
        "sys-process/btop",
        "sys-process/lsof",
        "sys-process/iotop",
        "x11-terms/kitty",
    }
    if c.is_enabled():
        worldSet.add("dev-util/ccache")
    ftPackageManager.update_world_set(worldSet)
    ftServiceManager.update_world_set(worldSet)
    ftSupportAllTermType.update_world_set(worldSet)
    if bHasMemTest:
        ftMemTest.update_world_set(worldSet)
    ftChrony.update_world_set(worldSet)
    ftZeroConf.update_world_set(worldSet)
    ftSshServer.update_world_set(worldSet)
    ftNetworkManager.update_world_set(worldSet)

    builder.action_update_world(worldSet)

    builder.add_and_run_custom_action("robustify_by_barkspider", ftAssistOs.get_custom_action_robustify_by_barkspider())

# step
with PrintLoadAvgThread(p.getIndentStr() + "- Building kernel..."):
    builder.action_install_kernel()     # do nothing
    builder.add_and_run_custom_action("real_build_kernel_and_initramfs", ftAssistOs.get_custom_action_build_kernel_and_initramfs(arch, diskFsUuid, p.getIndentStr()))

# step
p.printInfo("- Enabling services...")
if True:
    serviceList = []
    ftChrony.update_service_list(serviceList)
    ftZeroConf.update_service_list(serviceList)
    ftSshServer.update_service_list(serviceList)
    ftNetworkManager.update_service_list(serviceList)

    builder.action_enable_services(serviceList)

# step
p.printInfo("- Customizing...")
if True:
    builder.add_and_run_custom_action("set_root_password", gstage4.custom_actions.SetRootPassword(FmConst.userDefaultPassword))
    builder.add_and_run_custom_action("remove_usr_src_dir_content", gstage4.custom_actions.RemoveUsrSrcDirectoryContent())
    builder.add_and_run_custom_action("generate_machine_id", ftAssistOs.get_custom_action_generate_machine_id())
    builder.add_and_run_custom_action("config_services", ftAssistOs.get_custom_action_config_services())
    builder.add_and_run_custom_action("config_rcagent", ftAssistOs.get_custom_action_config_rcagent())
    # builder.add_and_run_custom_action("enable_console_service", ftAssistOs.get_custom_action_enable_console_service())    # FIXME

# step
p.printInfo("- Cleaning up...")
builder.action_cleanup()

# finish
builder.finish()
